<?php
/**
 * Project: HTPHouDuan
 * User: xilibo
 * Date: 2018/1/25
 */

namespace app\hpt\controller;

use think\Config;
use app\common\controller\CommonController;
use app\common\library\Mcrypter;
use app\common\library\HttpRequest;

/**
 * 网关控制器
 */
class GatewayController extends CommonController
{

    protected function _initialize()
    {
        parent::_initialize();
        $this->siteNodeName = $this->request->param('site', '');
        $this->encryptedParams = urldecode($this->request->param('params', ''));
        $this->encryptedParams = str_replace(' ', '+', $this->encryptedParams);
        Config::set('default_return_type', 'json');

    }

    /**
     * 网关入口
     */
    public function index()
    {
        static::$secKey = Config::get('api.secret_key', '');
        if (!empty(static::$secKey)){
            $this->jsonError('secret_key_error', 503);
        }

        if (empty($this->siteNodeName)) {
            return $this->jsonError('node_not_exists');
        } else if (empty($this->encryptedParams)){
            return $this->jsonError('param_error');
        } else {
            $this->siteNode = model('site_node')->getRow(['node_name' => $this->siteNodeName]);
            if (empty($this->siteNode) || empty($this->siteNode['node_url'])){
                return $this->jsonError('node_not_exists');
            }
        }

        static::$mcrypter = static::getMcrypter();

        return $this->handleRequest();
    }

    /**
     * 处理网关请求
     * @return [type] [description]
     */
    protected function handleRequest()
    {   
        $decryptedParams = static::$mcrypter->decrypt($this->encryptedParams);
        $this->decryptedParams = json_decode($decryptedParams, true);
        if (empty($this->decryptedParams['uname'])){
            return $this->jsonError('uname_empty');
        }

        if (empty($this->decryptedParams['act'])){
            return $this->jsonError('act_empty');
        }

        if (! empty($this->decryptedParams['game'])) {
            $this->decryptedParams['game'] = htmlspecialchars_decode(trim($this->decryptedParams['game']), ENT_QUOTES);
        }

		$gw_username = htmlspecialchars_decode(trim($this->decryptedParams['uname']), ENT_QUOTES);
		//$userInfo['user_pass'] = htmlspecialchars_decode(trim($this->decryptedParams['pwd']), ENT_QUOTES);
        $userInfo = [
			'user_login' => $gw_username,
		];
		$this->curUser = session('gw_user');
        //$sessUsername  = session('gw_user.user_login');
        $adminName = session('admin_name');
        
        if (empty($this->decryptedParams['utype']) || $this->decryptedParams['utype'] == 'user'){
            if (empty($this->curUser) || $gw_username != $this->curUser['user_login']){
				if ($gw_username != $this->curUser['user_login']){
					session('');
				}
                $userModel = model('user');
                $this->curUser = $userModel->getRow(['user_login' => $userInfo['user_login']]);
                if (empty($this->curUser)){
                    if (! $userModel->saveUser($userInfo)){
                        return $this->jsonError('user_register_fail');
                    }
                } else {
                    // if(! $userModel->validateUser($userInfo)){
                    //     $this->jsonError('user_login_fail');
                    // }
                }

                session('gw_user', $this->curUser);
            }
            $this->dispatchApi($this->decryptedParams);
        } else {
            $siteNodeModel = model('site_node');
            if ($this->decryptedParams['utype'] == 'admin'){
                if (! $siteNodeModel->validateAdmin($this->decryptedParams)){
                    return $this->jsonError('admin_login_fail', 403);
                }
                session('admin_name', 'ADMIN');
            } else if ($this->decryptedParams['utype'] == 'super_admin'){
                if (! $siteNodeModel->validateSuperAdmin($this->decryptedParams)){
                    return $this->jsonError('super_admin_login_fail', 403);
                }
                session('admin_name', 'SUPER_ADMIN');
            }
        }
    }

    /**
     * 解析参数并调度请求API
     * @param  [type] $paramInfo [description]
     */
    protected function dispatchApi($paramInfo)
    {
        $proxyConf = Config::get('api.proxy');
        $openApiList = Config::get('api.open');
        $code =  $this->siteNode['id'] . $this->curUser['id'] . (microtime(true) * 10000);
        $authCode =  static::$mcrypter->encrypt($code);
        $flagEntry = false;
        if (!in_array($this->decryptedParams['act'], $openApiList)) {
            if (! empty($paramInfo['game']) && $proxyConf[$this->decryptedParams['act']]['entry'] == true){
                $proxyConf[$this->decryptedParams['act']]['uri'] .= $paramInfo['game'] .
                    '?gw_username=' . $paramInfo['uname'] . '&code=' . $authCode;
                $flagEntry = true;
            }

            if (! empty($this->decryptedParams['act']['type']) && [$this->decryptedParams['act']]['type'] == 'html'){
                $jumpUrl = $proxyConf[$this->decryptedParams['act']]['uri'] . '?gw_username=' . $paramInfo['uname'] . '&code=' . $authCode;
                header('Location:' . $jumpUrl);
                exit;
            }
        }

        $apiActConf = $proxyConf[$paramInfo['act']];
        unset($paramInfo['password'], $paramInfo['act']);
        $nodeUrl = rtrim($this->siteNode['node_url'], '/') . '/';
        $reqParam['url'] = $nodeUrl . ltrim($apiActConf['uri'], '/');
        $reqParam['method'] = $apiActConf['method'];
        $paramInfo['gw_username'] = $paramInfo['uname'];
        unset($paramInfo['uname']);
        $reqParam['param'] = $paramInfo;
        if (! empty($proxyConf['pre_auth'])){
            $preParam = [
                'url' => $nodeUrl . $proxyConf['pre_auth'] . '?gw_username=' . $paramInfo['gw_username'] . '&code=' . $authCode .
                    '&node=' . $this->siteNodeName,
                'method' => 'GET',
            ];
            $preResult = HttpRequest::doGetRequest($preParam);
            $preResultArr = json_decode($preResult, true);
            if (empty($preResult) || (!isset($preResultArr['code']) || $preResultArr['code'] != 0)){
                echo $this->jsonError('authorize_fail')->getContent();
                exit;
            }
        }

        $method = 'do' . ucfirst(strtolower($apiActConf['method'])) . 'Request';
        $result = call_user_func_array([HttpRequest::class, $method], [$reqParam]);
        print_r($result);exit;
        if (empty(trim($result))){
            $errorCode = ['data' => ['node_url' => $nodeUrl . '?code=' . $code . '&username=' . $this->decryptedParams['uname']]];
            echo $this->jsonSuccess($errorCode)->getContent();
            exit;
        }

        if ($flagEntry){
            $result = $this->formatEntryData($result, $code, $nodeUrl);
        }

        echo $result;
        exit;
    }

    /**
     * 格式化入口数据
     * @param $entryData
     * @param string $code
     * @param string $nodeUrl
     * @return string
     */
    protected function formatEntryData($entryData, $code = '', $nodeUrl = '')
    {
        $userCode = '?code=' . $code . '&username=' . $this->decryptedParams['uname'];
        $entryData = (array)json_decode($entryData, true);
        if (isset($entryData[0]['play_url'])) {
            foreach ($entryData as $key => $data) {
                $entryData[$key]['play_url'] .= $userCode;
                $entryData[$key]['node_url'] = $nodeUrl . $userCode;
            }
        } else if (isset($entryData['play_url'])) {
            $entryData['play_url'] .= '?code=' . $code. '&username=' . $this->decryptedParams['uname'];
            $entryData = array_merge($entryData, ['node_url' => $nodeUrl . $userCode]);
        }
                
        return json_encode($entryData);
    }

    /**
     * 获取解密后的参数
     * @return [type] [description]
     */
    protected function getDecryptedParams()
    {
        return $this->decryptedParams;
    }

    /**
     * 获取请求的action
     * @return [type] [description]
     */
    protected function getRequestAct()
    {
        return $this->decryptedParams['act'];
    }

}
